﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using GIMS.Def.Arguments;
using GIMS.Def.Flags;
using GIMS.Def.Interfaces;
using GIMS.Def.Settings;
using System.Linq;


namespace GIMS.Def.Operators
{
    public enum Position
    {
        First,
        Between,
        Last
    }
    
    public abstract class Operator : IScriptPart
    {
        protected string name;
        protected string description;
        protected string instruction;
        protected string iconPath;
        protected Argument argument;
        protected Program possiblePrograms;
        protected Position position;
        protected List<Setting> settings;
        protected bool expectsMultipleInputs = false;
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// returns the name of the Operator
        /// </summary>
        public string Name
        {
            get
            {
                Contract.Ensures(!string.IsNullOrEmpty(name));
                return name;
            }
        }

        public string Description
        {
            get { return description; }
        }

        public Argument Argument
        {
            get
            {
                return argument;
            }
        }

        public string IconPath
        {
            get { return iconPath; }
        }
        

        /// <summary>
        /// Returns the program/s, in wich this command can be utilized
        /// </summary>
        public Program PossiblePrograms
        {
            get{ return possiblePrograms; }
        }

        /// <summary>
        /// Returns in wich position the Operator must be
        /// Input operator (Read) = first
        /// Output operator (Write) = last
        /// Other operators = Between (Between other two operators)
        /// </summary>
        public Position Position
        {
            get { return position; }
        }

        public List<Setting> Settings
        {
            get
            {
                return settings;
            }
        }

        public bool ExpectsMultipleInputs
        {
            get { return expectsMultipleInputs; }
        }      

        public virtual string CreateScriptPart()
        {
            string localSettingsScript="";
            string globalSettingsScript="";
            IEnumerable<Setting> globalSettingsList = GlobalSettings.Instance.Settings;

            foreach(Setting s in settings)
            {
                if(s.Active)
                {
                    localSettingsScript=string.Concat(localSettingsScript,s.CreateScriptPart()," ");
                    Setting globalSetting = (globalSettingsList.Where(x => x.Type == s.Type)).First();
                    if (globalSetting.Active)
                    {
                        globalSettingsScript = string.Concat(globalSetting.CreateScriptPart(), " ");
                    }
                }
            }
            return (string.Concat(localSettingsScript, CreateOperatorScript()," ", globalSettingsScript)).Trim();
        }


        protected virtual string CreateOperatorScript()
        {
            if(argument==null)
                return instruction; //for Operators wich have no argument
            else
                return string.Concat(instruction, " ", argument.CreateScriptPart());
        }


        protected void OnArgumentChanged(object sender, PropertyChangedEventArgs e)
        {
            NotifyPropertyChanged(String.Concat("Argument", ".", e.PropertyName));
        }

        protected void OnSettingChanged(object sender, PropertyChangedEventArgs e)
        {
            NotifyPropertyChanged(String.Concat("Setting", ".", e.PropertyName));
        }

        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
